package com.example.demo.base;

import com.baomidou.mybatisplus.mapper.BaseMapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.core.ResolvableType;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.Collection;
import java.util.Date;

public abstract class BaseServiceSupport<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> {

  private static final Integer DEFAULT_ENABLE = 0;

  /**
   * 实体类类型
   */
  private Class<T> entityClass;

  public BaseServiceSupport() {
    ResolvableType resolvableType = ResolvableType.forClass(getClass());
    entityClass = (Class<T>) resolvableType.getSuperType().getGeneric(1).resolve();
  }

  public IEntityWrapper<T> getWrapper(QueryBuilder<T> queryBuilder) {
    IEntityWrapper<T> entityWrapper = new IEntityWrapper<>();
    if (queryBuilder instanceof QueryBuilder && queryBuilder.getEntity() != null) {
      entityWrapper.setEntity(queryBuilder.getEntity());
    }
    if (!queryBuilder.isDeleted()&& FieldHandlerUtils.hasDeleteField(entityClass)) {
      entityWrapper.andNew().eq("deleted", DEFAULT_ENABLE);
    }
    if (queryBuilder == null) {
      return entityWrapper;
    }
    if (!CollectionUtils.isEmpty(queryBuilder.getFilters())) {
      for (Filter filter : queryBuilder.getFilters()) {
        if (filter == null) {
          continue;
        }
        toPredicate(entityWrapper, filter);
      }
    }
    if (!CollectionUtils.isEmpty(queryBuilder.getOrders())) {
      for (Order order : queryBuilder.getOrders()) {
        if (order == null) {
          continue;
        }
        toOrder(entityWrapper, order);
      }

    }
    return entityWrapper;
  }

  private void toPredicate(IEntityWrapper<T> wrapper, Filter filter) {
    String property = filter.getProperty();
    Filter.Operator operator = filter.getOperator();
    Object value = filter.getValue();
    Boolean ignoreCase = filter.getIgnoreCase();
    switch (operator) {
      case eq:
        if (value != null) {
          if (BooleanUtils.isTrue(ignoreCase) && value instanceof String) {
            wrapper.where(String.format("LOWER(%s) = {0}", property), ((String) value).toLowerCase());
          } else {
            wrapper.eq(property, value);
          }
        }
        break;
      case ne:
        if (value != null) {
          if (BooleanUtils.isTrue(ignoreCase) && value instanceof String) {
            wrapper.where(String.format("LOWER(%s) <> {0}", property), ((String) value).toLowerCase());
          } else {
            wrapper.ne(property, value);
          }
        }
        break;
      case gt:
        wrapper.gt(property, value);
        break;
      case lt:
        wrapper.lt(property, value);
        break;
      case ge:
        wrapper.ge(property, value);
        break;
      case le:
        wrapper.le(property, value);
        break;
      case like:
        if (value instanceof String) {
          if (BooleanUtils.isTrue(ignoreCase)) {
            wrapper.where(String.format("LOWER(%s) like {0}", property), ((String) value).toLowerCase());
          } else {
            wrapper.like(property, value.toString());
          }
        }
        break;
      case in:
        if (value instanceof Collection) {
          wrapper.in(property, (Collection<?>) value);
        } else if (value instanceof Object[]) {
          wrapper.in(property, Arrays.asList((Object[]) value));
        } else if (value instanceof String) {
          wrapper.in(property, (String) value);
        }
        break;
      case notIn:
        if (value instanceof Collection) {
          wrapper.notIn(property, (Collection<?>) value);
        } else if (value instanceof Object[]) {
          wrapper.notIn(property, Arrays.asList(value));
        } else if (value instanceof String) {
          wrapper.notIn(property, (String) value);
        }
        break;
      case isNull:
        wrapper.isNull(property);
        break;
      case isNotNull:
        wrapper.isNotNull(property);
        break;
      case between:
        if (value != null && value instanceof Object[]) {
          Object[] values = (Object[]) value;
          if (values.length == 2) {
            wrapper.between(property, values[0], values[1]);
          }
        }
        break;
      case groupBy:
        wrapper.groupBy(property);
        break;
      case and:
        if(value!=null) {
          wrapper.andNew(property, value);
        }
        break;
      case andNew:
        wrapper.andNew();
        break;
      case orNew:
        wrapper.orNew();
        break;
      case or:
        wrapper.or();
        break;
      case limit:
        if (value != null) {
          if (value instanceof Integer[]) {
            Integer[] values = (Integer[]) value;
            if (values.length == 2) {
              wrapper.limit(values[0], values[1]);
            }
          } else if (value instanceof Integer) {
            wrapper.limit((Integer) value);
          }
        }
        break;
      case eqFmtDate:
        if (value != null && value instanceof Object[]) {
          Object[] values = (Object[]) value;
          if (values.length == 2) {
            if (values[0] instanceof Date && values[1] instanceof String) {
              wrapper.where(String.format("DATE_FORMAT(%s,'%s') = DATE_FORMAT({0},'%s')", property, values[1],values[1]), DateFormatUtils.format((Date)values[0],"yyyy-MM-dd HH:mm:ss"));
            }
          }
        }
        break;
    }
  }

  public void toOrder(IEntityWrapper<T> wrapper, Order order) {
    String property = order.getProperty();
    Order.Direction direction = order.getDirection();
    switch (direction) {
      case asc:
        wrapper.orderBy(property, true);
        break;
      case desc:
        wrapper.orderBy(property, false);
        break;
    }
  }

}
